/* -*- c++ -*-
*
* bookmarkbar.cpp
*
* Copyright (C) 2005, 2006 Petter Stokke <ummo@hellokitty.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/

#include "bookmarkbar.h"

#include <kdebug.h>
#include <klocale.h>
#include <kinstance.h>
#include <klistview.h>
#include <kstatusbar.h>
#include <kprogress.h>
#include <kconfig.h>
#include <kstandarddirs.h>
#include <kcombobox.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <dom/html_document.h>

#include <qsplitter.h>
#include <qcursor.h>
#include <qfile.h>
#include <qdatastream.h>
#include <qtimer.h>

#include "taglist.h"
#include "postlist.h"
#include "prettylabel.h"

BookmarkBar::BookmarkBar( KInstance *inst, QObject *parent, QWidget *widgetParent, QString &desktopName, const char* name )
        : KonqSidebarPlugin( inst, parent, widgetParent, desktopName, name )
{
    m_config = new KConfig( "konqsidebar_deliciousrc", false, false );

    KIconLoader* icons = KGlobal::iconLoader();

    m_api = new DeliciousAPI( this );
    m_collection = new Collection( m_api, this );

    m_top = new QVBox( widgetParent );
    m_main = new QVBox( m_top );
    m_topLabel = new PrettyLabel( m_main );
    m_topLabel->setText( i18n( "top label without username", "<b>del.icio.us</b>" ) );
    m_splitter = new QSplitter( Vertical, m_main );
    m_tagList = new TagList( m_api, m_splitter );
    QVBox* postBox = new QVBox( m_splitter );
    m_search = new KComboBox( postBox );
    m_search->setEditable( true );
    m_search->setDuplicatesEnabled( false );
    m_search->setInsertionPolicy( QComboBox::NoInsertion );
    m_search->setMaxCount( 5 );
    m_search->setSizePolicy( QSizePolicy::Expanding, QSizePolicy::Fixed );
    m_search->insertItem( icons->loadIcon( "find", KIcon::Small ) );
    m_searchTimer = new QTimer( m_search );
    connect( m_search, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotSearchTyping() ) );
    connect( m_search, SIGNAL( returnPressed( const QString& ) ), this, SLOT( slotSubmitSearch( const QString& ) ) );
    connect( m_searchTimer, SIGNAL( timeout() ), this, SLOT( slotSearch() ) );
    m_postLabel = new PrettyLabel( postBox );
    m_postList = new PostList( m_api, postBox );
    m_statusBar = new KStatusBar( m_top );
    m_progressBar = new KProgress( m_statusBar );
    m_statusBar->addWidget( m_progressBar, 0, true );
    m_progressBar->setHidden( true );

    m_config->setGroup( "Interface" );
    m_postList->setNewWindowByDefault( m_config->readBoolEntry( "NewWindowByDefault", false ) );

    setDeliciousUser( m_api->user() );

    connect( m_tagList, SIGNAL( tagsSelected( const QStringList& ) ),
             this, SLOT( loadTags( const QStringList& ) ) );
    /*
    connect( m_tagList, SIGNAL( globalTagSelected( const QString& ) ),
             this, SLOT( loadGlobalTag( const QString& ) ) );
    */
    connect( m_tagList, SIGNAL( tagRenamed( const QString&, const QString& ) ),
             this, SLOT( slotTagRenamed( const QString&, const QString& ) ) );
    connect( m_tagList, SIGNAL( pleaseRefresh() ),
             this, SLOT( slotRefresh() ) );
    connect( m_tagList, SIGNAL( urlDropped( const KURL&, const QStringList& ) ),
             this, SLOT( submitURL( const KURL&, const QStringList& ) ) );
    connect( m_postList, SIGNAL( openPostDefaultAction( Post* ) ),
             this, SLOT( openPostDefaultAction( Post* ) ) );
    connect( m_postList, SIGNAL( openPost( Post* ) ),
             this, SLOT( openPost( Post* ) ) );
    connect( m_postList, SIGNAL( openPostInNewWindow( Post* ) ),
             this, SLOT( openPostInNewWindow( Post* ) ) );
    connect( m_postList, SIGNAL( editPost( Post* ) ),
             this, SLOT( editPost( Post* ) ) );
    connect( m_postList, SIGNAL( changedNewWindowByDefault( bool ) ),
             this, SLOT( setNewWindowByDefault( bool ) ) );
    connect( m_postList, SIGNAL( urlDropped( const KURL&, const QStringList& ) ),
             this, SLOT( submitURL( const KURL&, const QStringList& ) ) );
    connect( m_postList, SIGNAL( submitURL( const KURL&, const QStringList& ) ),
             this, SLOT( submitURL( const KURL&, const QStringList& ) ) );
    connect( m_postList, SIGNAL( titleChanged( const QString& ) ),
             this, SLOT( slotSetPostTitle( const QString& ) ) );
    connect( m_api, SIGNAL( jobStatusText( const QString& ) ),
             this, SLOT( slotUpdateStatusText( const QString& ) ) );
    connect( m_api, SIGNAL( jobProgress( KIO::filesize_t, KIO::filesize_t ) ),
             this, SLOT( slotUpdateProgress( KIO::filesize_t, KIO::filesize_t ) ) );
    connect( m_api, SIGNAL( jobDone() ),
             this, SLOT( slotClearStatusBar() ) );
    connect( m_api, SIGNAL( userChanged( const QString& ) ),
             this, SLOT( setDeliciousUser( const QString& ) ) );

    loadCache();
    m_postList->setTagFilter( QStringList() );
    slotRefresh();
}

BookmarkBar::~BookmarkBar()
{}

void BookmarkBar::handleURL( const KURL& )
{}

void BookmarkBar::submitURL( const KURL& url, const QStringList& tags )
{
    kdDebug() << "Dropped URL " << url << " into tags \"" << tags << "\"" << endl;
    DOM::HTMLDocument doc;
    doc.setAsync( false );
    doc.load( DOM::DOMString( url.url() ) );
    // TODO: Provide some feedback while the document is loaded above.
    kdDebug() << "Doc title: \"" << doc.title() << "\"" << endl;
    KURL submitUrl( "http://del.icio.us/" );
    submitUrl.addPath( m_api->user() );
    submitUrl.addQueryItem( "v", "4" );
    // submitUrl.addQueryItem( "noui", QString::null );
    submitUrl.addQueryItem( "jump", "close" );
    submitUrl.addQueryItem( "url", url.url() );
    submitUrl.addQueryItem( "title", doc.title().string() );
    // submitUrl.addQueryItem( "notes", default user notes can go here if needed );
    emit createNewWindow( submitUrl, KParts::URLArgs() );
}

void BookmarkBar::setNewWindowByDefault( bool _newWindowByDefault )
{
    m_config->setGroup( "Interface" );
    m_config->writeEntry( "NewWindowByDefault", _newWindowByDefault );
    m_config->sync();
}

void BookmarkBar::slotUpdateStatusText( const QString& text )
{
    m_statusBar->message( text );
}

void BookmarkBar::slotUpdateProgress( KIO::filesize_t processed, KIO::filesize_t total )
{
    m_progressBar->setTotalSteps( total );
    m_progressBar->setProgress( processed );
    m_progressBar->setHidden( false );
}

void BookmarkBar::slotClearStatusBar()
{
    m_statusBar->clear();
    m_progressBar->setHidden( true );
}

void BookmarkBar::slotRefresh()
{
    GetPostsJob * job = m_api->getPosts( m_collection->lastUpdate() );
    BookmarkAPIJob* j = dynamic_cast<BookmarkAPIJob*>( job );
    Q_ASSERT( j );
    connect( j, SIGNAL( success( BookmarkAPIJob* ) ),
             this, SLOT( slotGotPosts( BookmarkAPIJob* ) ) );
    connect( j, SIGNAL( failed( BookmarkAPIJob* ) ), this, SLOT( slotRecoverFromError() ) );
    m_main->setEnabled( false );
    m_top->setCursor( QCursor( WaitCursor ) );
}

/*
void BookmarkBar::slotFetchUserIfNeeded()
{
    if (!m_api->user().isEmpty()) {
        slotRecoverFromError();
        return;
    }
    GetUserJob* job = m_api->getUser();
    connect(job, SIGNAL(gotUser(const QString&)), this, SLOT(setDeliciousUser(const QString&)));
    connect(job, SIGNAL(failed()), this, SLOT(slotRecoverFromError()));
}
*/

void BookmarkBar::slotRecoverFromError()
{
    m_main->setEnabled( true );
    m_top->unsetCursor();
}

void BookmarkBar::loadCache()
{
    QFile cacheFile( locateLocal( "apps", "konqsidebar_delicious/cache" ) );
    if ( !cacheFile.exists() || cacheFile.size() < 8 )
        return ;
    if ( cacheFile.open( IO_ReadOnly ) ) {
        QDataStream cache( &cacheFile );
        m_collection->loadData( cache );
        cacheFile.close();
        m_tagList->updateTags( m_collection );
        m_postList->updatePosts( m_collection );
    }
}

void BookmarkBar::slotGotPosts( BookmarkAPIJob* job )
{
    slotRecoverFromError();

    GetPostsJob* j = dynamic_cast<GetPostsJob*>( job );
    Q_ASSERT( j );

    if ( j->noUpdateNeeded() )
        return ;

    m_collection->clear();
    m_collection->addPosts( j->posts() );
    m_collection->setLastUpdate( j->updateTime() );

    m_tagList->updateTags( m_collection );
    m_postList->updatePosts( m_collection );

    QFile cacheFile( locateLocal( "apps", "konqsidebar_delicious/cache" ) );
    if ( cacheFile.open( IO_WriteOnly | IO_Truncate ) ) {
        QDataStream cache( &cacheFile );
        m_collection->saveData( cache );
        cacheFile.close();
    }
}

void BookmarkBar::slotTagRenamed( const QString& oldTag, const QString& newTag )
{
    m_collection->renameTag( oldTag, newTag );

    if ( m_postList->tagFilter().contains( oldTag ) ) {
        QStringList filter = m_postList->tagFilter();
        int pos = filter.findIndex( oldTag );
        filter[ pos ] = newTag;
        m_postList->setTagFilter( filter );
    }
    m_postList->updatePosts( m_collection );
}

void BookmarkBar::setDeliciousUser( const QString& user )
{
    slotRecoverFromError();
    m_topLabel->setText( i18n( "top label with username", "<b>%1@del.icio.us</b>" ).arg( user ) );
}

void BookmarkBar::slotSetPostTitle( const QString& title )
{
    m_postLabel->setText( title );
}

void BookmarkBar::loadTags( const QStringList& tags )
{
    m_postList->setTagFilter( tags );
}

/*
void BookmarkBar::loadGlobalTag( const QString& tag )
{
    GetGlobalTagJob * job = m_api->getGlobalTag( tag );
    connect( job, SIGNAL( gotGlobalTag( const QValueList<Post>&, const QString& ) ),
             this, SLOT( slotGotGlobalTag( const QValueList<Post>&, const QString& ) ) );
    connect( job, SIGNAL( failed() ), this, SLOT( slotRecoverFromError() ) );
    m_main->setEnabled( false );
    m_top->setCursor( QCursor( WaitCursor ) );
}

void BookmarkBar::slotGotGlobalTag( const QValueList<Post>& posts, const QString& tag )
{
    slotRecoverFromError();
    m_postLabel->setText( i18n( "global tag header", "<b>Tag: *%1</b>" ).arg( tag ) );
    m_postList->setTagFilter( tag );
    m_postList->updatePosts( posts );
}
*/

void BookmarkBar::openPostDefaultAction( Post* post )
{
    if ( m_postList->newWindowByDefault() )
        openPostInNewWindow( post );
    else
        openPost( post );
}

void BookmarkBar::openPost( Post* post )
{
    emit openURLRequest( post->url(), KParts::URLArgs() );
}

void BookmarkBar::openPostInNewWindow( Post* post )
{
    emit createNewWindow( post->url(), KParts::URLArgs() );
}

void BookmarkBar::editPost( Post* post )
{
    KURL url( "http://del.icio.us/" );
    url.addPath( post->user() );
    url.addQueryItem( "url", post->url().url() );
    url.addQueryItem( "jump", "no" );
    emit createNewWindow( url, KParts::URLArgs() );
}

void BookmarkBar::slotSearchTyping()
{
    m_searchTimer->start( 500, true );
}

void BookmarkBar::slotSearch()
{
    QString s( m_search->currentText() );
    if ( s.isEmpty() )
        return ;
    m_tagList->clearSelection();
    m_postList->setSearchFilter( s );
}

void BookmarkBar::slotSubmitSearch( const QString& s )
{
    if ( m_searchTimer->isActive() ) {
        m_searchTimer->stop();
        slotSearch();
    }
    if ( s.isEmpty() )
        return ;
    KIconLoader * icons = KGlobal::iconLoader();
    if ( !m_search->contains( s ) )
        m_search->insertItem( icons->loadIcon( "find", KIcon::Small ), s );
    m_search->lineEdit() ->setText( s );
    m_search->lineEdit() ->selectAll();
}



extern "C"
{
    void * create_konqsidebar_bookmarkbar( KInstance * instance, QObject * par, QWidget * widp, QString & desktopname, const char * name ) {
        return new BookmarkBar( instance, par, widp, desktopname, name );
    }

    bool add_konqsidebar_bookmarkbar( QString * fn, QString * param, QMap<QString, QString> *map ) {
        Q_UNUSED( param );

        map->insert ( "Type", "Link" );
        map->insert ( "URL", "" );
        map->insert ( "Icon", "delicious" );
        map->insert ( "Name", i18n ( "del.icio.us" ) );
        map->insert ( "Open", "true" );
        map->insert ( "X-KDE-KonqSidebarModule", "konqsidebar_bookmarkbar" );
        fn->setLatin1 ( "bookmarkbar.desktop" );
        return true;
    }
};

#include "bookmarkbar.moc"
